package partner

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/binny_w/go-util"
	util2 "gitee.com/binny_w/go-util/v2"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"strings"
)

type TableModel struct {
	Table        *util2.MysqlTable
	OrderBys     map[string]string
	InfoFixer    func(c *gin.Context, row *util2.MysqlRow) error
	QueryFixer   func(c *gin.Context, k string, v []string, p []any) (w, k1 string, p1 []any, ctn bool, err error)
	ListFixer    func(c *gin.Context, row *util2.MysqlRow) error
	InsertFixer  func(c *gin.Context, row *util2.MysqlRow) error
	UpdateFixer  func(c *gin.Context, row *util2.MysqlRow) error
	QueryKeyword *QueryKeyword
	CommonModel
	Alias          string
	OrderByDefault string
	SoColumns      []string
	PageSizeMax    int64
}

var _ Model = (*TableModel)(nil)

func NewTableModelEasy(tableName string, db *util2.MysqlClient) *TableModel {
	mt := util2.NewMysqlTable(db, tableName)
	return NewTableModel(mt, "", nil)
}

func NewTableModel(mt *util2.MysqlTable, alias string, qkd *QueryKeyword) *TableModel {
	if alias == "" {
		alias = util.StrFromCamel(mt.Name, "-")
	}
	m := &TableModel{
		Alias:     alias,
		Table:     mt,
		OrderBys:  make(map[string]string),
		SoColumns: make([]string, 0),
		CommonModel: CommonModel{
			handlers: make(map[string]map[string][]gin.HandlerFunc),
		},
		PageSizeMax: 50,
	}
	if qkd == nil {
		qkd = _defaultQueryKeyword
	}
	m.QueryKeyword = qkd

	path := fmt.Sprintf("/%s", alias)
	_ = m.RegisterGinHandler(http.MethodGet, path, m.list)    // list
	_ = m.RegisterGinHandler(http.MethodPost, path, m.insert) // insert
	path = fmt.Sprintf("/%s/%s", alias, ":id")
	_ = m.RegisterGinHandler(http.MethodGet, path, m.info)      // info
	_ = m.RegisterGinHandler(http.MethodDelete, path, m.delete) // delete
	_ = m.RegisterGinHandler(http.MethodPatch, path, m.update)  // update

	return m
}

func (m *TableModel) info(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		WriteJsonError(c, 601, "请求 Id 为空")
		return
	}
	if row, err := m.Table.GetOne(c, id); err != nil {
		WriteJsonError(c, 602, err.Error())
	} else if row == nil {
		WriteJsonError(c, http.StatusNotFound, "数据不存在")
	} else {
		if m.InfoFixer != nil {
			if err = m.InfoFixer(c, row); err != nil {
				WriteJsonError(c, 603, err.Error())
				return
			}
		}
		WriteJsonSuccess(c, row)
	}
}

func (m *TableModel) list(c *gin.Context) {
	where := "1 = 1 "
	params := make([]any, 0)
	var page, pageSize int64 = 1, 20
	order, cols := "", ""
	var bln bool
	if c.Request != nil {
		if i, err := strconv.ParseInt(c.DefaultQuery(m.QueryKeyword.Page, "1"), 10, 64); err == nil && i > 0 {
			page = i
		}
		if i, err := strconv.ParseInt(c.DefaultQuery(m.QueryKeyword.PageSize, "20"), 10, 64); err == nil && i > 0 {
			pageSize = i
		}
		if m.PageSizeMax > 1 && pageSize > m.PageSizeMax {
			pageSize = m.PageSizeMax
		}
		col := c.Query(m.QueryKeyword.SoColumn)
		word := c.Query(m.QueryKeyword.SoWord)
		if col != "" && word != "" && util2.InArray(col, m.SoColumns) {
			where += fmt.Sprintf("AND `%s` LIKE ? ", col)
			params = append(params, "%"+word+"%")
		}
		allQueryKeywords := m.QueryKeyword.Words()
		for k := range c.Request.URL.Query() {
			v := c.QueryArray(k)
			if k == "" || strings.Contains(k, "`") || len(v) < 1 {
				continue
			}
			if isIn := util2.InArray(k, allQueryKeywords); isIn {
				continue
			}
			if m.QueryFixer != nil {
				ws := ""
				k1 := ""
				ctn := false
				var err error
				if ws, k1, params, ctn, err = m.QueryFixer(c, k, v, params); err == nil {
					k = k1
					if ws != "" {
						where += ws + " "
					}
					if ctn {
						continue
					}
				}
			}
			if l := len(v); l == 1 {
				where += fmt.Sprintf("AND `%s` = ? ", k)
				params = append(params, strings.TrimSpace(v[0]))
			} else {
				s := make([]string, l)
				for i := 0; i < l; i++ {
					s[i] = "?"
					params = append(params, v[i])
				}
				where += fmt.Sprintf("AND `%s` IN (%s) ", k, strings.Join(s, ", "))
			}
		}
	}
	order, bln = m.OrderBys[c.Query(m.QueryKeyword.OrderBy)]
	if !bln {
		order = m.OrderByDefault
	}
	rows := make([]*util2.MysqlRow, 0)
QUERY:
	if totalItem, totalPage, curPage, err := m.Table.SelectPage(c, func(_ context.Context, row *util2.MysqlRow) error {
		if m.ListFixer != nil {
			if err := m.ListFixer(c, row); err != nil {
				return err
			}
		}
		rows = append(rows, row)
		return nil
	}, page, pageSize, where, order, cols, params...); err != nil {
		if errors.Is(err, util2.ErrMysqlPageTooLarge) {
			page = totalPage
			goto QUERY
		} else {
			WriteJsonError(c, 604, err.Error())
		}
	} else {
		WriteJsonSuccess(c, gin.H{
			"total_item": totalItem,
			"page_size":  pageSize,
			"total_page": totalPage,
			"cur_page":   curPage,
			"rows":       rows,
		})
	}
}

func (m *TableModel) insert(c *gin.Context) {
	if c.Request == nil {
		WriteJsonError(c, 605, "请求参数为空")
		return
	}
	ok := false
	row := util2.MysqlRow{}
	_ = c.PostForm("id")
	for k := range c.Request.PostForm {
		v := c.PostFormArray(k)
		if k == "" || k == "id" || len(v) == 0 {
			continue
		}
		if !ok {
			ok = true
		}
		if len(v) == 1 {
			row[k] = strings.TrimSpace(v[0])
		} else {
			row[k] = v
		}
	}
	if !ok {
		WriteJsonError(c, 606, "请求参数无效")
		return
	}
	if m.InsertFixer != nil {
		if err := m.InsertFixer(c, &row); err != nil {
			WriteJsonError(c, 607, err.Error())
			return
		}
	}
	if newId, err := m.Table.Insert(c, &row); err != nil {
		WriteJsonError(c, 608, err.Error())
	} else {
		c.Set("new_id", newId)
		WriteJsonSuccess(c, gin.H{
			"new_id": newId,
		})
	}
}

func (m *TableModel) delete(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		WriteJsonError(c, 609, "请求参数为空")
		return
	}
	if num, err := m.Table.DeleteByIds(c, id); err != nil {
		WriteJsonError(c, 610, err.Error())
	} else {
		WriteJsonSuccess(c, gin.H{
			"deleted": num,
		})
	}
}

func (m *TableModel) update(c *gin.Context) {
	if c.Request == nil {
		WriteJsonError(c, 611, "请求参数为空")
		return
	}
	ok := false
	row := util2.MysqlRow{}
	id := c.Param("id")
	_ = c.PostForm("id")
	for k := range c.Request.PostForm {
		v := c.PostFormArray(k)
		if k == "" || k == "id" || len(v) == 0 {
			continue
		}
		if !ok {
			ok = true
		}
		if len(v) == 1 {
			row[k] = strings.TrimSpace(v[0])
		} else {
			row[k] = v
		}
	}
	if !ok || id == "" {
		WriteJsonError(c, 612, "请求参数无效")
		return
	}
	if m.UpdateFixer != nil {
		if err := m.UpdateFixer(c, &row); err != nil {
			WriteJsonError(c, 613, err.Error())
			return
		}
	}
	if num, err := m.Table.UpdateById(c, &row, id); err != nil {
		WriteJsonError(c, 614, err.Error())
	} else {
		WriteJsonSuccess(c, gin.H{
			"updated": num,
		})
	}
}
